#ifndef _B_PLUS_TREE_NODE_DATA_HPP__
#define _B_PLUS_TREE_NODE_DATA_HPP__ 1
#include <Types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <FTSTypes.h>
#include <string.h>
#include <FTSSException.hpp>
#include <map>
// подобран, чтобы весь лист по размеру был ~одной странице памяти (4096)
#define LEAF_DATA_SIZE 408 
#define RAW_LEAF_DATA_SIZE LEAF_DATA_SIZE - 2 * sizeof(INT_64)

/**
* @file BPlusTreeNodeLeafData.hpp
* @brief nodes and leafs data for b plus storage
*/
namespace FTSS{
	/**
	* @struct BPlusTreeNodeData BPlusTreeNodeLeafData.hpp <BPlusTreeNodeLeafData.hpp>
	* @brief Node Data - pair of word hash and chunk number
	*/
	struct BPlusTreeNodeData{
		TokenHash_t iWordHash;
		UINT_64 iChunkNumber;
		// хранит в <iWordHash, 0> iDF данного слова
		// stores in <iWordHash, 0> iDF of this word
		// inverse document frequence
		INT_64 iDF;
		// хранит в себе номер последнего iChunkNumber для быстрого доступа
		// акутальная информация всегда хранится в <iWordHash, 0>
		// stores number of last chunk for word with this hash
		// actually information always stores in <iWordHash, 0>
		UINT_64 iSize;

		/**
		* @Constructor
		* @param iIHash - hash word
		* @param iIChunkNum - current chunk number
		* @param iISize - max chunk number
		*/
		inline BPlusTreeNodeData(TokenHash_t iIHash = 0,
				  UINT_64 iIChunkNum = 0,
				  INT_64  iIDF = 0,
 				  UINT_32 iISize = 0)
		: iWordHash(iIHash), iChunkNumber(iIChunkNum), iDF(iIDF), iSize(iISize) {}

		/**
		* @brief Copy Constructor
		* @param oNode - node to copy
		*/
		BPlusTreeNodeData(const BPlusTreeNodeData &oNode){
			this->iWordHash = oNode.iWordHash;
			this->iChunkNumber = oNode.iChunkNumber;
			this->iSize = oNode.iSize;
			this->iDF = oNode.iDF;
		}

		/**
		* @brief operator ==
		* @param oNode - node to compare
		*/
		bool operator == (const BPlusTreeNodeData & oNode){
			return this->iWordHash == oNode.iWordHash &&
			       this->iChunkNumber == oNode.iChunkNumber;
		}

		/**
		* @brief operator !=
		* @param oNode - node to compare
		*/
		bool operator != (const BPlusTreeNodeData & oNode){
			return !(this->iWordHash == oNode.iWordHash && 
			         this->iChunkNumber == oNode.iChunkNumber);
		}

		/**
		* @brief operator <
		* @param oNode - node to compare
		*/
		bool operator < (const BPlusTreeNodeData & oNode){
			return  (this->iWordHash < oNode.iWordHash) ||
					((this->iWordHash <= oNode.iWordHash) && 
					 (this->iChunkNumber < oNode.iChunkNumber));
		}

		/**
		* @brief operator <=
		* @param oNode - node to compare
		*/
		bool operator <= (const BPlusTreeNodeData & oNode){
			return  (this->iWordHash < oNode.iWordHash) ||
				((this->iWordHash <= oNode.iWordHash) && 
				 (this->iChunkNumber <= oNode.iChunkNumber));
		}
		
		/**
		* @brief operator >=
		* @param oNode - node to compare
		*/
		bool operator >= (const BPlusTreeNodeData & oNode){
			return  ! (this->iWordHash < oNode.iWordHash ||
			 	   ((this->iWordHash <= oNode.iWordHash) && 
				    (this->iChunkNumber < oNode.iChunkNumber)));
		}
		 /**
		 * @brief operator =
		 * @param oNode - node to compare
		 */
public:		BPlusTreeNodeData & operator = (const BPlusTreeNodeData &oNode){
			this->iWordHash = oNode.iWordHash;
			this->iChunkNumber = oNode.iChunkNumber;
			this->iSize = oNode.iSize;
			this->iDF = oNode.iDF;
			return *this;
		}

		/**
		* @brief Destructor
		*/
public:		~BPlusTreeNodeData() throw(){}
	};// Node Data

	/**
	* @struct BPlusTreeLeafData BPlusTreeNodeLeafData.hpp <BPlusTreeNodeLeafData.hpp>
	* @brief Leaf Data - data and data size
	*/
	struct BPlusTreeLeafData {
 		INT_64 iDataSize;
		CHAR_P pData;
		INT_64 *copy_num;

		/**
		* @brief Constructor
		* @param iISize - data size
		* @param pIData - data
		*/
		inline BPlusTreeLeafData(INT_64 iIDataSize = 0,
				  CHAR_P pIData = NULL)
		 {
			iDataSize = 0;
			copy_num = new INT_64(1);
			if (iIDataSize > getFreeSize()){
				fprintf(stderr, "too big document entry save a part\n");
//				throw LogicException("Document is too lage for one leaf");
			}
			if (pIData != NULL){
				pData = new CHAR_8[RAW_LEAF_DATA_SIZE];
				memcpy(pData,
				       pIData,
				       (iIDataSize <= getFreeSize() ? iIDataSize : getFreeSize()));
				iDataSize = (iIDataSize <= getFreeSize() ? iIDataSize : getFreeSize());
			} else { pData = NULL; }
		}
		
		/**
		* @brief append new data part to the end of leaf
		* @param pIData new data part
		* @oaram iIDataSize size of new part data
		*/
		inline CHAR_P append(CCHAR_P pIData, INT_32 iIDataSize){
			if (pData == NULL){ pData = new CHAR_8[RAW_LEAF_DATA_SIZE]; iDataSize = 0;}
			if (copy_num == NULL) {copy_num = new INT_64; (*copy_num) = 0;}
			CHAR_P dest = pData + iDataSize;
			iDataSize += iIDataSize;
			return(CHAR_P) memcpy(dest, pIData, iIDataSize);
		}
		/**
		* @brief get size of struct data leaf
		* @return size of struct
		*/
		inline static INT_32 getSizeStruct(){ return LEAF_DATA_SIZE; }

		/**
		* @brief get size of data in leaf data
		* @return get size of data
		*/
		inline static INT_32 getSizeData() { return RAW_LEAF_DATA_SIZE - sizeof(INT_64);}

		/**
		* @brief get free size in data leaf
		* @return number of bytes free for write
		*/
		inline UINT_32 getFreeSize(){ return RAW_LEAF_DATA_SIZE - sizeof(INT_64) -iDataSize; }

		/**
		* @brief Destructor
		*/
		~BPlusTreeLeafData() throw(){
			dispose();
		}

		/**
		* @brief operator ==
		* @param oLeaf - leaf to compare
		*/
		bool operator == (const BPlusTreeLeafData &oLeafData){
			return iDataSize == oLeafData.iDataSize &&
			       pData == oLeafData.pData;
		}

		/**
		* @brief operator !=
		* @param oLeaf - leaf to compare
		*/
		bool operator != (const BPlusTreeLeafData &oLeafData){
			return !(iDataSize == oLeafData.iDataSize &&
			       pData == oLeafData.pData);
		}

	
		/**
		 * @brief Copy Constructor
		 * @param oLeafData object to copy
		 */
		
		inline BPlusTreeLeafData(const BPlusTreeLeafData &oLeafData){
			this->pData = oLeafData.pData;
			this->iDataSize = oLeafData.iDataSize;
			this->copy_num = oLeafData.copy_num;
			++*copy_num;
		}

		inline BPlusTreeLeafData& operator = (const BPlusTreeLeafData &oLeafData){
			if (this != &oLeafData){
				dispose();
				this->pData = oLeafData.pData;
				this->iDataSize = oLeafData.iDataSize;
				this->copy_num = oLeafData.copy_num;
				++(*copy_num);
			}
			return *this;
		}
private:
		void dispose(){
			if (--copy_num == 0){
				delete copy_num;
				delete pData;
			}
		}

	};// Leaf Data
}// namespace FTSS

#endif
